<?php

namespace App\Http\Middleware;

use Closure;
use Log;
use App\Utils\CommonUtils;
use App\Utils\ReturnUtils;
use App\Utils\RouteLists;
use Illuminate\Http\Request;
use App\Models\User;
use Auth;
use DB;
use App\Models\Common\Stopwords;
use Dotenv;
use App\Cache\BaseCache;
use Config;
use Cache;
use App\Models\Common\ContentStats;
use App\Models\Common\Comment;
use App\Models\Common\ContentUgc;

class BeforeMiddleware {

    protected $DEBUG = TRUE; //调试接口总开关

    public function handle($request, Closure $next) {
        //写入环境变量 env文件
        if ($request->input('debug') == 'debug') {// 先加载者先成功
            (new Dotenv\Dotenv(__DIR__ . '/../../../env/', 'debug.env'))->load();
        }
        $env_file = env($_SERVER['HTTP_HOST']);
        try {
            (new Dotenv\Dotenv(__DIR__ . '/../../../env/', $env_file . '.env'))->load();
        } catch (InvalidArgumentException $e) {
            
        }

        /** *********************测试函数********************** */
//		$this->test_function();
        DB::connection(env('MYSQL_CONNECTION', 'mysql'))->enableQueryLog(); //开启sql语言分析
        /*         * ************************************************** */
        $returnUtils = new ReturnUtils($request);

        $CUR_IP = $request->ip();
        $is_white_ip = FALSE;
        $i = 0;
        while (1) {
            $i++;
            $index_ip = env('IP_WHITE_'.$i, 'END');
            if ($index_ip == 'END') {
                break;
            } else if ($CUR_IP && $index_ip == $CUR_IP || $index_ip == trim(substr($CUR_IP, 0, -strlen(strrchr($CUR_IP, '.')))) ) {
                $is_white_ip = TRUE;
                break;
            }
        }
        if (!$is_white_ip) {
            //黑名单
            $IPBlackCache = new BaseCache();
            $IPBlackCache->method = 'get';
            $IPBlackCache->cacheName = 'IPBlack';
            $IPBlackCache->cachePar = array($CUR_IP); //集合
            //IP 访问记录
            $IPBlackHistoryCache = new BaseCache();
            $IPBlackHistoryCache->method = 'get';
            $IPBlackHistoryCache->cacheName = 'IPBlackHistory';
            $IPBlackHistoryCache->cachePar = array($CUR_IP); //集合

            $caheObject = $IPBlackCache->HandleCache();
            if ($caheObject !== 'NO_CACHE') {
                return $returnUtils->returnError($returnUtils->return['ERROR_LIMIT_IP']);
            }
            $caheObject = $IPBlackHistoryCache->HandleCache();
            if ($caheObject !== 'NO_CACHE') {
                $times = $caheObject;
                if ($times > 1000 && !env('APP_DEBUG', FALSE)) {
                    //加入黑名单
                    $IPBlackCache->method = 'put';
                    $IPBlackCache->HandleCache();
                    Log::info('IP黑名单:+' . $CUR_IP . ' Times:' . $times);
                    return $returnUtils->returnError($returnUtils->return['ERROR_LIMIT_IP']);
                }
                $times = $times > 1 ? ++$times : 1;
                if ($times > 0 && $times % 100 === 0) {
                    Log::info('IP:' . $CUR_IP . ' Times = n*100,n =' . $times / 100);
                }
                $IPBlackHistoryCache->method = 'increment';
                $IPBlackHistoryCache->HandleCache();
            } else {
                $IPBlackHistoryCache->method = 'put';
                $IPBlackHistoryCache->cacheValue = 1;
                $IPBlackHistoryCache->HandleCache();
            }
        }
        $action = trim(strrchr($request->route()[1]['uses'], '@'), '@');

        //参数验证
        $routelists = with(new RouteLists())->lists;
        foreach ($routelists as $route => $value) {
            if ($action == $route && isset($value['version'])) {
                //对比版本，查找相应规则
                $version = $request->input('v', '');
                if (isset($value['version'][$version])) {
                    $rules_code = $value['version'][$version];
                } else if (isset($value['version']['max'])) {
                    $rules_code = $value['version']['max'];
                } else {
                    $message = array('en' => '', 'zh-CN' => 'routelists 异常错误');
                    return $returnUtils->returnError($returnUtils->return['ERROR_UNKNOWN'], $message);
                }
                if (!isset($value['rules'][$rules_code])) {
                    $message = array('en' => '', 'zh-CN' => 'routelists 异常错误');
                    return $returnUtils->returnError($returnUtils->return['ERROR_UNKNOWN'], $message);
                }
                $rules = $value['rules'][$rules_code]; //得到验证规则
                //参数校验param
                $params = $request->all();
                //是否校验tn
                //        ty     String   //系统类型 a:android i:ios tv:电视端
                //        v      String   //软件版本号  1.0.0
                //        dk     String   //设备的唯一标示
                //        tn     String   //请求
                //        userId String   //若用户登录时传入用户id，若没有登陆时 ‘#ray’+ 随机16位字符 
                //        注：tn = 登陆时获取的用户token／随机16位字符包含数字 + md5(userId+ty+v+dk,32)，注意顺序不能改变，这样做的目的是为了每次接口都先校验请求的合法性
                if (isset($rules['isCheckTn']) && $rules['isCheckTn'] === TRUE) {
                    $ty = $request->input('ty');
                    $v = $request->input('v');
                    $dk = $request->input('dk');
                    $tn = $request->input('tn');
                    $userId = $request->input('userId');
                    if (substr($tn, -32) !== md5($userId . $ty . $v . $dk)) {
                        return $returnUtils->returnError($returnUtils->return['ERROR_PARAMETER_VLAUE_TOKEN']);
                    }
                    $tn = substr($tn, 0, strlen($tn) - 32);
                    $request->merge(array('tn' => $tn));
                }
                //isStrict 非常严格
                if ($rules['isStrict'] === 2 && count($params) !== count($rules['parameters'])) {
                    $message = array('en' => '', 'zh-CN' => '参数个数不正确');
                    return $returnUtils->returnError($returnUtils->return['ERROR_PARAMETER_TOTAL'], $message);
                }
                $ip_withe = TRUE;
                //IP 白名单
                if(isset($rules['ipWithe']) && is_array($rules['ipWithe'])){
                    foreach ($rules['ipWithe'] as $value) {
                        $ip_withe = FALSE;
                        if($value == $CUR_IP || $value == trim(substr($CUR_IP, 0, -strlen(strrchr($CUR_IP, '.'))))){
                            $ip_withe = TRUE;
                            break;
                        }
                    }
                }
                if(!$ip_withe){
                    $message = array('en' => '', 'zh-CN' => '不在IP白名单内:');
                    return $returnUtils->returnError($returnUtils->return['ERROR_IP_WHITE'], $message);
                }
                foreach ($params as $key => $param) {
                    
                    if (!array_key_exists($key, $rules['parameters']) && $rules['isStrict'] !== 0) {
                        $message = array('en' => '', 'zh-CN' => '未知参数:' . $key);
                        return $returnUtils->returnError($returnUtils->return['ERROR_PARAMETER_UNKONWN'], $message);
                    }
                    if (isset($rules['parameters'][$key]['isNull']) && $rules['parameters'][$key]['isNull'] === FALSE && $param === '') {
                        $message = array('en' => '', 'zh-CN' => '参数不能为空:' . $key);
                        return $returnUtils->returnError($returnUtils->return['ERROR_PARAMETER_NULL'], $message);
                    }
                    if ($param !== '' && isset($rules['parameters'][$key]['length']) && ($rules['parameters'][$key]['length']['min'] > mb_strlen($param, 'utf-8') || $rules['parameters'][$key]['length']['max'] < mb_strlen($param, 'utf-8') )) {
                        $message = array('en' => '', 'zh-CN' => '参数长度限制在:' . $key);
                        return $returnUtils->returnError($returnUtils->return['ERROR_PARAMETER_LENGTH'], $message);
                    }
                    if ($param !== '' && isset($rules['parameters'][$key]['value'])) {
                        $valueIsRight = FALSE; //标记是否通过value验证
                        foreach ($rules['parameters'][$key]['value'] as $val) {
                            //特殊参数：isPhone,isEmail,isNumber,isFloat
                            if ($val === 'isPhone' && with(new CommonUtils())->isEmailorPhone($param) === 2) {
                                $valueIsRight = TRUE;
                                break;
                            } else if ($val === 'isEmail' && with(new CommonUtils())->isEmailorPhone($param) === 1) {
                                $valueIsRight = TRUE;
                                break;
                            } else if ($val === 'isNumber' && is_numeric($param)) {
                                if ($key === 'size' && $param <= 0) { //size 大于 0
                                    break;
                                }
                                $valueIsRight = TRUE;
                                break;
                            } else if ($val === 'isFloat' && ( is_float($param) || is_numeric($param) )) {
                                $valueIsRight = TRUE;
                                break;
                            } else if ($val === $param) {
                                //普通固定参数
                                $valueIsRight = TRUE;
                                break;
                            }
                        }
                        if (!$valueIsRight) {
//							echo '参数格式有误'.$key;
                            return $returnUtils->returnError($returnUtils->return['ERROR_PARAMETER_VLAUE']);
                        }
                    }
                    if ($param !== '' && isset($rules['parameters'][$key]['isUser'])) { //username 是否验证用户名(isUser:true 验证用户必须存在 false 验证用户必须不存在)：目前用户名只有phone 和email
                        $ret = with(new CommonUtils())->isEmailorPhone($param);
                        if ($ret === 1) {
                            $info['email'] = $param;
                            //判断是否已经注册过
                            if (with(new User($request))->isBindEmail($info) != 1 && $rules['parameters'][$key]['isUser']) {
                                return $returnUtils->returnError($returnUtils->return['ERROR_USER_UNREGISTER']);
                            } elseif (with(new User($request))->isBindEmail($info) == 1 && !$rules['parameters'][$key]['isUser']) {
                                return $returnUtils->returnError($returnUtils->return['ERROR_USER_ALREADY_REGISTER']);
                            }
                        } else if ($ret === 2) {
                            //判断是否已经注册过
                            $info['phone'] = $param;
                            if (with(new User($request))->isBindPhone($info) != 1 && $rules['parameters'][$key]['isUser']) {
                                return $returnUtils->returnError($returnUtils->return['ERROR_USER_UNREGISTER']);
                            } elseif (with(new User($request))->isBindPhone($info) == 1 && !$rules['parameters'][$key]['isUser']) {
                                return $returnUtils->returnError($returnUtils->return['ERROR_USER_ALREADY_REGISTER']);
                            }
                        } else {
                            return $returnUtils->returnError($returnUtils->return['ERROR_USER_UNREGISTER']);
                        }
                    }
                    //解析UUid 至 id
                    if ($param !== '' && isset($rules['parameters'][$key]['isUUid']) && $rules['parameters'][$key]['isUUid']) { //isUUid 
                        $uid = with(new CommonUtils())->getId($param);
                        $request->merge(array($key => $uid));
                    }

                    if ($param !== '' && isset($rules['parameters'][$key]['isUserId']) && $rules['parameters'][$key]['isUserId']) { //userId 是否用户ID存在数据库
                        $uid = with(new CommonUtils())->getId($param);
                        if (!$uid) {
                            return $returnUtils->returnError($returnUtils->return['ERROR_USER_GETINFO']); //用户不存在，获取用户失败
                        }
//                        if(!with(new User())->getUserByUuid($param)){
//							return $returnUtils->returnError($returnUtils->return['ERROR_USER_GETINFO']); //用户不存在，获取用户失败
//						}
                    }
                    if ($param !== '' && isset($rules['parameters'][$key]['isLiveId']) && $rules['parameters'][$key]['isLiveId']) { //liveId 是否直播ID存在数据库
                        $uid = with(new CommonUtils())->getId($param);
                        if (!$uid) {
                            return $returnUtils->returnError($returnUtils->return['ERROR_USER_GETINFO']); //用户不存在，获取用户失败
                        }
                    }

                    if ($param !== '' && isset($rules['parameters'][$key]['checkStop']) && $rules['parameters'][$key]['checkStop']) { //敏感词过滤
                        if (with(new Stopwords())->isExistStopWords($param)) {//存在敏感词
                            return $returnUtils->returnError($returnUtils->return['ERROR_STOPWORD_LIMIT']);
                        }
                    }
                }
                $request->merge(array('loginStatus' => '0'));
                //登录验证
                if ($rules['authType'] === 1) { //客户端
                    $tn = $request->input('tn');
                    $uid = $request->input('userId');
                    $user = with(new User($request))->getUserModel((int) $uid);
                    //检查用户是否	
                    if (!$user || !isset($user->token) || $user->token !== $tn || $user->token_expires < time()) {
                        if ($rules['auth']) {
                            return $returnUtils->returnError($returnUtils->return['ERROR_USER_TOKEN']);
                        }
                    } else {
                        $request->merge(array('loginStatus' => '1'));
                    }
                } else if ($rules['authType'] === 2) { //web登录
//					取auth
                    $user = Auth::user();
                    if (!$user) {
                        if ($rules['auth'] == TRUE) {
                            return $returnUtils->returnError($returnUtils->return['ERROR_USER_UNLOGIN']);
                        }
                    }
                }
                //是否debug
                if ($this->DEBUG == TRUE && $rules['debug'] == TRUE) {
                    return $rules['return'];
                }
                break;
            }
            continue;
        }
        return $next($request);
    }

    private function test_function() {
//		$returnUtils = new ReturnUtils();
//		$arr =array();
//		foreach ($returnUtils->return as $key => $value) {
//			$arr[$value['code']] = $value['name']['zh-CN'];
//		}
//		echo json_encode($arr,JSON_UNESCAPED_UNICODE|JSON_UNESCAPED_SLASHES);
//		exit();
    }

}
